﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SimpleCompiler
{
    public class RuntimeVariableScope
    {
        internal class Scope
        {
            public Scope(bool enteringFunction)
            {
                isFunction = enteringFunction;
            }
            public readonly bool isFunction = false;
            public readonly Dictionary<string, Variable> dicVariables = new Dictionary<string, Variable>();
        }

        Dictionary<string, StatementFunction> dicParsedFunctions = new Dictionary<string, StatementFunction>();

        internal StatementFunction GetFunctionStatementByName(string functionName)
        {
            return dicParsedFunctions[functionName];
        }

        public RuntimeVariableScope(Dictionary<string, StatementFunction> dicParsedFunctions)
        {
            this.dicParsedFunctions = dicParsedFunctions;
            variablesList.Add(new Scope(false));
        }



        public Dictionary<string, string> TopVariables()
        {
            Dictionary<string, string> vars = new Dictionary<string, string>();
            foreach (var var in variablesList.First().dicVariables)
            {
                vars[var.Key] = var.Value.value.ValueString();
            }
            return vars;
        }

        private string DebugVariables => String.Join(" | ", variablesList.Select(item => $"{item.isFunction}. " + String.Join(", ", item.dicVariables.Select(item => $"{item.Key} -> {item.Value.value.ValueString()}"))));



        private List<Scope> variablesList = new List<Scope>();
        public TypeNotNone Load(string name)
        {            
            for (int index = variablesList.Count - 1; index >= 0; index--)
            {
                var scope = variablesList[index];
                if (scope.dicVariables.ContainsKey(name))
                {
                    return scope.dicVariables[name].value;
                }
                else
                {
                    if (scope.isFunction)
                    {
                        var firstScope = variablesList.First();
                        if (firstScope.dicVariables.ContainsKey(name))
                        {
                            return firstScope.dicVariables[name].value;
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false);
                            return null;
                        }
                    }
                }
            }
            System.Diagnostics.Debug.Assert(false);
            return null;
        }

        public void InitVariable(string name, TypeNotNoneName value)
        {
            var dic = variablesList.Last().dicVariables;
            System.Diagnostics.Debug.Assert(!dic.ContainsKey(name));
            dic[name] = new Variable() { name = name, value = TypeNotNone.CreateInstance(value) };
        }

        public void InitVariable(string name, Variable value)
        {
            var dic = variablesList.Last().dicVariables;
            System.Diagnostics.Debug.Assert(!dic.ContainsKey(name));
            dic[name] = value;
        }


        public void PushScope(bool enteringFunction)
        {
            variablesList.Add(new Scope(enteringFunction));
        }

        public void PopScope()
        {
            if (variablesList.Count > 0)
            {
                variablesList.RemoveAt(variablesList.Count - 1);
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
        }
    }
}
